! VSemiletov, 08.2011
module Data_Transducer

    integer :: nTransducers = 0 ! number of transducers
    
    type tTransducer
        character(280) :: name
        integer :: nameLength
        character(280) :: fileOutput
        character(280) :: fileCellsInput ! the name of the file from read data for CellsOut
        logical :: CalcCellsFromContour = .true. ! .true. = calc. Cells from contour, else read Cells from file
        
        logical :: PointLocation = .false. ! point output !
        real(8) :: Location(3)             ! coordinates for point output
        
        ! for cells otput
        integer :: nCellsOut = 0 ! number of cells for output data
        integer :: nCellsOutGlobal = 0 ! number of cells for output data in all processors
        integer,allocatable :: CellsOut(:) ! number of cell for output
        
        ! for faces output
        integer :: nFacesOut = 0 ! number of faces for output data
        integer :: nFacesOutGlobal = 0 ! number of faces for output data in all processors
        integer,allocatable :: FacesOut(:) ! number of face for output

        integer :: nVars = 0                ! number of vars for output
        logical :: Pres = .false.
        logical :: Uvel = .false.
        logical :: Vvel = .false.
        logical :: Wvel = .false.
        logical :: Temp = .false. ! (nVars)
        logical :: dPdtOut = .false. ! flag for output time derivativ of Pressure
        real(8),allocatable :: Vars(:,:) ! (nCellsOut,nVars)
        real(8),allocatable :: VarsFace(:,:) ! (nFacesOut,nVars)

        logical :: AllProcsWriteOwnData = .true. ! .false. !

        ! Output types:
        logical :: TableOut = .true.  ! On/Off output table
        logical :: SliceOut = .false. ! On/Off output slices
        logical :: Average = .false.  ! Output average values
        logical :: EveryStep = .false. ! On/Off output every step, only for asynchrony

        logical :: Hollow = .false. ! to take into account both inside and surface's cells
        logical :: insideOnly = .false. ! to take into account only inside cells

        logical :: LeftDiscActive=.false., RightDiscActive=.false. ! on/off
        real(8) :: CenterDir(3)=(/0.,1.0,0./)
        real(8) :: Length = 0.2 ! cylinder length
        real(8) :: factor = 1.0d0

        real(8) :: timeStart=0.0d0, timeEnd=1.0d10  ! time interval for output
        real(8) :: dTimeOut ! how often to output data
        integer :: ndTimeOut = 0 ! number of output times
        
        real(8) :: StepX,StepY,StepZ
        
        integer :: BoundaryOut ! output: intersection between btype(BoundaryOut) and Transducer's Cells
        character(50) :: BoundaryOutFile
        
       	real(8),allocatable :: recv(:)               ! for sending Volume between Points from diff procs
        integer,allocatable :: recvCounts(:)
        integer,allocatable :: rDispls(:)

       	real(8),allocatable :: recvFace(:)
        integer,allocatable :: recvCountsFace(:)
        integer,allocatable :: rDisplsFace(:)
        
        ! 2Dmesh normal to the boundary
        real(8) :: InitVal = 0
        real(8) :: ScaleFactor = 0
        integer :: nLayers = 0
    end type tTransducer
    
    type(tTransducer),allocatable :: Transducer(:)
    
contains
    
subroutine defCellsTransducer()
use Data_cfoam, only: processor,ie,rank
use Data_Mesh, only: nCells,nFaces, meshPoints,meshCellPoints, meshCells,meshCellCenters
use Acoustics, only: LeftDiscActive,RightDiscActive, CenterDir, Length, factor
implicit none

    integer :: i,j,k, jj, iCell,iFace
    integer :: LengthName
    real(8) :: CoorCell(3,8)
    character(50) name
    integer,allocatable :: auxCellsOut(:), auxFacesOut(:)
    real(8) :: r(3)
    logical :: extraCell, extraFace

    allocate(auxCellsOut(nCells))
    allocate(auxFacesOut(nFaces))

    do i = 1,nTransducers
        if(Transducer(i)%PointLocation)then

            call CalcSourceLocation(Transducer(i)%Location(1:3), iCell)
        
            Transducer(i)%nCellsOut = 1
            allocate(Transducer(i)%CellsOut(1))
            Transducer(i)%CellsOut(1) = iCell
            
            Transducer(i)%nFacesOut = 0
        
            Transducer(i)%nVars = 5
            allocate(Transducer(i)%Vars(Transducer(i)%nCellsOut,Transducer(i)%nVars))
            !allocate(Transducer(i)%VarsFace(Transducer(i)%nFacesOut,Transducer(i)%nVars))

            cycle
        end if

        if(Transducer(i)%CalcCellsFromContour)then

            LeftDiscActive = Transducer(i)%LeftDiscActive
            RightDiscActive = Transducer(i)%RightDiscActive
            CenterDir(1:3) = Transducer(i)%CenterDir(1:3)
            Length = Transducer(i)%Length
            factor = Transducer(i)%factor
            LengthName = 0
            do j = 1,280
                if(Transducer(i)%fileCellsInput(j:j).eq.' ')then
                    LengthName = j
                    exit
                end if
            end do

            call ReadContourData(Transducer(i)%fileCellsInput(1:LengthName))

            Transducer(i)%nCellsOut = 0
            auxCellsOut = 0
            do iCell=1,nCells
                extraCell = .false.
                do j = 1,Transducer(i)%nCellsOut
                    r(1:3) = abs(meshCellCenters(1:3,iCell) - meshCellCenters(1:3,auxCellsOut(j)))
                    if(r(1).lt.Transducer(i)%StepX.and. &
                               r(2).lt.Transducer(i)%StepY.and. &
                               r(3).lt.Transducer(i)%StepZ)then
                       extraCell = .true. 
                       exit
                    end if
                end do
                if(extraCell) cycle
                
                do jj=1,8
                    CoorCell(1:3,jj)=meshPoints(1:3,meshCellPoints(jj,iCell))
                end do

                call meshCellTransducerOut(CoorCell,iCell,Transducer(i)%Hollow,Transducer(i)%insideOnly, &
                                           Transducer(i)%nCellsOut,auxCellsOut)
            end do

            allocate(Transducer(i)%CellsOut(Transducer(i)%nCellsOut))

            Transducer(i)%CellsOut = 0
            do iCell=1,Transducer(i)%nCellsOut
                Transducer(i)%CellsOut(iCell) = auxCellsOut(iCell)
            end do

            ! define FacesOut:
            Transducer(i)%nFacesOut = 0
            do iCell=1,Transducer(i)%nCellsOut
                do j = 1,6
                    iFace = meshCells(j,auxCellsOut(iCell))
                    
                    extraFace = .false.
                    do k = 1,Transducer(i)%nFacesOut
                        if(iFace.eq.auxFacesOut(k))then
                            extraFace = .true.
                            exit
                        end if
                    end do
                    if(extraFace) cycle
                    Transducer(i)%nFacesOut = Transducer(i)%nFacesOut + 1
                    auxFacesOut(Transducer(i)%nFacesOut) = iFace
                end do
            end do

            allocate(Transducer(i)%FacesOut(Transducer(i)%nFacesOut))
            Transducer(i)%FacesOut = 0

            do iFace=1,Transducer(i)%nFacesOut
                Transducer(i)%FacesOut(iFace) = auxFacesOut(iFace)
            end do

            name(1:10) = 'CellTrans_'
            name(11:50) = Transducer(i)%name(1:40)
            call writeCellsOutTransducer(i,processor(1:ie)//name)
        else
            call readCellsOutTransducer(i,processor(1:ie)//Transducer(i)%fileCellsInput)
        end if

        if(Transducer(i)%SliceOut)then
            if(Transducer(i)%dPdtOut)then
                Transducer(i)%nVars = 6
            else
                Transducer(i)%nVars = 5
            end if
        end if
        allocate(Transducer(i)%Vars(Transducer(i)%nCellsOut,Transducer(i)%nVars))
        allocate(Transducer(i)%VarsFace(Transducer(i)%nFacesOut,Transducer(i)%nVars))

!        write(*,*) 'nVars=', Transducer(i)%nCellsOut, rank

        Transducer(i)%Vars(:,:) = 0.0d0
        Transducer(i)%VarsFace(:,:) = 0.0d0

!        cycle

        call WriteBoundaryOut(Transducer(i)%nCellsOut,Transducer(i)%CellsOut,Transducer(i)%BoundaryOut, &
                            Transducer(i)%BoundaryOutFile, &
                            Transducer(i)%InitVal,Transducer(i)%ScaleFactor,Transducer(i)%nLayers)

!        do iCell = 1,Transducer(i)%nCellsOut
!            write(*,'(a15,3f8.3)') '@@ CellsOut = ', meshCellCenters(1:3,Transducer(i)%CellsOut(iCell))
!        end do
    end do

    deallocate(auxCellsOut)
    deallocate(auxFacesOut)

end subroutine defCellsTransducer

subroutine writeCellsOutTransducer(nTrans,name)
use Data_Mesh, only: meshCellCenters,meshFaceCenters
implicit none
    integer,intent(in) :: nTrans ! number of Transducer
    character(*),intent(in) :: name

    integer :: i
    integer :: OpenFile

    open(11,file=name,IOSTAT=OpenFile)
    if (OpenFile.ne.0) then
	    write(*,*) '@@ Fatal Error: File open error '//name
	    STOP '@@ Fatal Error!'
    end if

    write(11,'(a50)') Transducer(nTrans)%name
    write(11,*) 'nCellsOut:'
    write(11,*) Transducer(nTrans)%nCellsOut
    write(11,*) 'CellsOut  meshCellCenters(1:3)'

    do i=1,Transducer(nTrans)%nCellsOut
        write(11,'(i15,3f8.3)') Transducer(nTrans)%CellsOut(i), &
                                meshCellCenters(1:3,Transducer(nTrans)%CellsOut(i))
    end do

    write(11,*) 'nFacesOut:'
    write(11,*) Transducer(nTrans)%nFacesOut
    write(11,*) 'FacesOut  meshFaceCenters(1:3)'

    do i=1,Transducer(nTrans)%nFacesOut
        write(11,'(i15,3f8.3)') Transducer(nTrans)%FacesOut(i), &
                                meshFaceCenters(1:3,Transducer(nTrans)%FacesOut(i))
    end do

    
    close(11)
    return
end subroutine writeCellsOutTransducer

subroutine readCellsOutTransducer(nTrans,name)
implicit none
    integer,intent(in) :: nTrans ! number of Transducer
    character(*),intent(in) :: name

    integer :: i
    integer :: OpenFile

    open(11,file=name,IOSTAT=OpenFile)
    if (OpenFile.ne.0) then
	    write(*,*) '@@ Fatal Error: File open error '//name
	    STOP '@@ Fatal Error!'
    end if

    read(11,*) Transducer(nTrans)%name
    read(11,*) 
    read(11,*) Transducer(nTrans)%nCellsOut
    read(11,*)

    allocate(Transducer(nTrans)%CellsOut(Transducer(nTrans)%nCellsOut))

    do i=1,Transducer(nTrans)%nCellsOut
        read(11,*) Transducer(nTrans)%CellsOut(i)
    end do

    read(11,*)
    read(11,*) Transducer(nTrans)%nFacesOut
    read(11,*)

    do i=1,Transducer(nTrans)%nFacesOut
        read(11,*) Transducer(nTrans)%FacesOut(i)
    end do


    close(11)
    return
end subroutine readCellsOutTransducer

end module Data_Transducer

